package com.atu.rtc.factory;

import android.app.Activity;

import androidx.annotation.NonNull;

import com.atu.rtc.DateChannelObserver;
import com.atu.rtc.MySdpObserver;
import com.atu.rtc.PeerConnectionObserver;
import com.atu.rtc.bean.Candidate;
import com.atu.rtc.bean.Desc;
import com.atu.rtc.bean.Message;
import com.atu.rtc.utils.Convert;

import org.java_websocket.client.WebSocketClient;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.DataChannel;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RendererCommon;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractCapturer {
    protected MySdpObserver observer;

    protected abstract int getWidth();

    protected abstract int getHeight();

    protected abstract Activity getActivity();

    protected abstract VideoCapturer createVideoCapturer();

    protected abstract WebSocketClient getClient();

    protected PeerConnection peerConnection;
    protected SurfaceViewRenderer localSurfaceView;

    protected void send(String text) {
        if (getClient() != null && getClient().isOpen()) {
            getClient().send(text);
        }
    }

    protected void close() {
        localSurfaceView.clearImage();
        localSurfaceView.release();
        localSurfaceView = null;
        peerConnection.close();
        peerConnection = null;
    }

    /**
     * 创建本地视频
     *
     * @param localSurfaceView
     */
    protected void startLocalVideoCapture(SurfaceViewRenderer localSurfaceView, PeerConnectionFactory peerConnectionFactory, PeerConnection peerConnection, List<String> streamList, EglBase eglBase) {
        VideoSource videoSource = peerConnectionFactory.createVideoSource(true);
        SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(Thread.currentThread().getName(), eglBase.getEglBaseContext());
        VideoCapturer videoCapturer = createVideoCapturer();
        videoCapturer.initialize(surfaceTextureHelper, getActivity(), videoSource.getCapturerObserver());
        videoCapturer.startCapture(getWidth(), getHeight(), 60); // width, height, frame per second
        VideoTrack videoTrack = peerConnectionFactory.createVideoTrack("videotrack", videoSource);
        videoTrack.addSink(localSurfaceView);
        MediaStream localMediaStream = peerConnectionFactory.createLocalMediaStream("localVideoStream");
        localMediaStream.addTrack(videoTrack);
        peerConnection.addTrack(videoTrack, streamList);
        peerConnection.addStream(localMediaStream);
    }

    /**
     * 创建本地音频
     */
    protected void startLocalAudioCapture(PeerConnectionFactory peerConnectionFactory, PeerConnection peerConnection, List<String> streamList) {
        //语音
        MediaConstraints audioConstraints = new MediaConstraints();
        //回声消除
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation", "true"));
        //自动增益
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl", "true"));
        //高音过滤
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googHighpassFilter", "true"));
        //噪音处理
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));
        AudioSource audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
        AudioTrack audioTrack = peerConnectionFactory.createAudioTrack("audiotrack", audioSource);
        MediaStream localMediaStream = peerConnectionFactory.createLocalMediaStream("localAudioStream");
        localMediaStream.addTrack(audioTrack);
        audioTrack.setVolume(10);
        peerConnection.addTrack(audioTrack, streamList);
        peerConnection.addStream(localMediaStream);
    }

    protected void createPeerConnection(SurfaceViewRenderer localSurfaceView) {
        //Initialising PeerConnectionFactory
        PeerConnectionFactory.InitializationOptions initializationOptions = PeerConnectionFactory.InitializationOptions.builder(getActivity())
                .setEnableInternalTracer(true)
                .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
//                .setFieldTrials("WebRTC-SupportVP9/Enabled/")
                .createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);
        //创建EglBase对象
        EglBase eglBase = EglBase.create();
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
//        options.disableEncryption = true;
//        options.disableNetworkMonitor = true;
        PeerConnectionFactory peerConnectionFactory = PeerConnectionFactory.builder()
                .setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglBase.getEglBaseContext()))
                .setVideoEncoderFactory(new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), true, true))
                .setOptions(options)
                .createPeerConnectionFactory();
        // 配置STUN穿透服务器  转发服务器
        List<PeerConnection.IceServer> iceServers = new ArrayList<>();
        PeerConnection.IceServer iceServer = PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer();
        iceServers.add(iceServer);

        List<String> streamList = new ArrayList<>();

        PeerConnection.RTCConfiguration configuration = new PeerConnection.RTCConfiguration(iceServers);
//        configuration.enableDtlsSrtp = true;
//        configuration.enableDscp = true;

        PeerConnectionObserver connectionObserver = getObserver();
//        MediaConstraints mediaConstraints = new MediaConstraints();
//        mediaConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
        peerConnection = peerConnectionFactory.createPeerConnection(configuration, connectionObserver);


        /*
        DataChannel.Init 可配参数说明：
        ordered：是否保证顺序传输；
        maxRetransmitTimeMs：重传允许的最长时间；
        maxRetransmits：重传允许的最大次数；
        */
        DataChannel.Init init = new DataChannel.Init();
        DataChannel channel = peerConnection.createDataChannel("channel", init);
        DateChannelObserver channelObserver = new DateChannelObserver();
        connectionObserver.setObserver(channelObserver);
        initSurfaceview(localSurfaceView, eglBase);
        startLocalVideoCapture(localSurfaceView, peerConnectionFactory, peerConnection, streamList, eglBase);
        startLocalAudioCapture(peerConnectionFactory, peerConnection, streamList);
        initObserver(peerConnection);
    }

    /**
     * 初始化iew
     *
     * @param localSurfaceView
     */
    protected void initSurfaceview(SurfaceViewRenderer localSurfaceView, EglBase eglBase) {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                localSurfaceView.init(eglBase.getEglBaseContext(), null);
                localSurfaceView.setMirror(true);
                localSurfaceView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
                localSurfaceView.setKeepScreenOn(true);
                localSurfaceView.setZOrderMediaOverlay(true);
                localSurfaceView.setEnableHardwareScaler(false);
            }
        });
    }


    /**
     * 拨打电话
     */
    protected void createOffer(PeerConnection peerConnection) {
        MediaConstraints mediaConstraints = new MediaConstraints();
        mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        mediaConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
        mediaConstraints.optional.add(new MediaConstraints.KeyValuePair("trickle", "true"));
        peerConnection.createOffer(observer, mediaConstraints);
    }

    protected void createAnswer(PeerConnection peerConnection) {
        MediaConstraints mediaConstraints = new MediaConstraints();
        mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        peerConnection.createAnswer(observer, mediaConstraints);
    }

    protected void initObserver(PeerConnection peerConnection) {
        observer = new MySdpObserver() {
            @Override
            public void onCreateSuccess(SessionDescription sessionDescription) {
                //将会话描述设置在本地
                peerConnection.setLocalDescription(this, sessionDescription);
                SessionDescription localDescription = peerConnection.getLocalDescription();
                SessionDescription.Type type = localDescription.type;
                //接下来使用之前的WebSocket实例将offer发送给服务器
                if (type == SessionDescription.Type.OFFER) {
                    //呼叫
                    Message message = new Message();
                    message.setToId(1002L);
                    message.setType(2);
                    Desc desc = new Desc();

                    desc.setSdp(sessionDescription.description);
                    desc.setType("offer");
                    message.setDesc(desc);
                    send(Convert.toJson(message));
                } else if (type == SessionDescription.Type.ANSWER) {
                    //应答
//                    answer(sessionDescription);
                } else if (type == SessionDescription.Type.PRANSWER) {
                    //再次应答

                }
            }
        };

    }


    @NonNull
    protected PeerConnectionObserver getObserver() {
        return new PeerConnectionObserver() {
            @Override
            public void onIceCandidate(IceCandidate iceCandidate) {
                super.onIceCandidate(iceCandidate);

                Message message = new Message();
                message.setToId(1002L);
                message.setType(3);
                Candidate candidate = new Candidate();
                candidate.setCandidate(iceCandidate.sdp);
                candidate.setSdpMid(iceCandidate.sdpMid);
                candidate.setSdpMLineIndex(iceCandidate.sdpMLineIndex);
                message.setCandidate(candidate);
                send(Convert.toJson(message));
            }

            @Override
            public void onAddStream(MediaStream mediaStream) {
                super.onAddStream(mediaStream);
                List<VideoTrack> videoTracks = mediaStream.videoTracks;
                if (videoTracks != null && videoTracks.size() > 0) {
                    VideoTrack videoTrack = videoTracks.get(0);
                    if (videoTrack != null) {
                    }
                }
                List<AudioTrack> audioTracks = mediaStream.audioTracks;
                if (audioTracks != null && audioTracks.size() > 0) {
                    AudioTrack audioTrack = audioTracks.get(0);
                    if (audioTrack != null) {
                        audioTrack.setVolume(10);
                    }
                }
            }
        };
    }
}
